using System;
using System.Linq.Expressions;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;

namespace Kym.Testing
{
    internal class ShouldBeInRange<T, V> : IShouldBeInRange<T> where T : IComparable
    {
        private readonly T value;
        private readonly V range;

        public ShouldBeInRange(T value, V range)
        {
            this.value = value;
            this.range = range;
        }

        public void from(T other)
        {
            var otherParam = Expression.Parameter(typeof (T), "other");
            var rangeParam = Expression.Parameter(typeof (V), "range");

            var subtraction = Expression.Subtract(otherParam, rangeParam);
            var addition = Expression.Add(otherParam, rangeParam);

            var otherMinusRange = Expression.Lambda<Func<T, V, T>>(subtraction, otherParam, rangeParam).Compile();
            var otherPlusRange = Expression.Lambda<Func<T, V, T>>(addition, otherParam, rangeParam).Compile();

            Assert.That(value, Is.GreaterThanOrEqualTo(otherMinusRange(other, range)) & Is.LessThanOrEqualTo(otherPlusRange(other, range)));
        }
    }
}